package com.manda.smart.hub.common.service;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.ServiceLoaderUtil;
import cn.hutool.core.util.URLUtil;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

/**
 * SPI 机制加载器
 *
 * @author hongda.li
 */
public final class SpiLoader {
    /**
     * SPI 实例缓存
     */
    private static final Map<Class<?>, List<?>> SPI_CACHE = new ConcurrentHashMap<>(16);

    private SpiLoader() {
    }

    /**
     * 从缓存中优先加载 SPI 实例
     * 若缓存中不存在，则根据反射加载并缓存其结果
     *
     * @param type 指定的实例类型
     * @param <T>  实例泛型
     * @return 加载结果
     */
    public static <T> List<T> loadFromCache(Class<T> type) {
        return SPI_CACHE.computeIfAbsent(type, key -> SpiLoader.load(type))
                .stream()
                .map(type::cast)
                .toList();
    }

    /**
     * 通过反射加载 SPI 实例
     * 每次调用均会重新加载 SPI 实例
     *
     * @param type 指定的实例类型
     * @param <T>  实例泛型
     * @return 加载结果
     */
    public static <T> List<T> load(Class<T> type) {
        return ServiceLoaderUtil.loadList(type);
    }

    /**
     * 其它自定义的 SPI 扩展机制
     * 底层原理为读取类路径下的指定资源
     * 并根据资源文件转为对应的实例
     * 若存在多个资源，则依次将这些资源合并为字符串流
     *
     * @param resourceName 指定的资源名称
     * @return 字符串流
     */
    public static Stream<String> loadStream(String resourceName) {
        return ResourceUtil.getResources(resourceName)
                .stream()
                .map(URLUtil::getStream)
                .map(IoUtil::readUtf8);
    }
}
